package miage.rest.resource.candidature;

import com.thoughtworks.xstream.XStream;
import java.sql.Connection;
import java.sql.Date;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import miage.rest.db.Database;
import miage.rest.form.Form;
import miage.rest.model.Candidat;
import miage.rest.model.Candidature;
import miage.rest.model.SessionDiplome;
import miage.rest.resource.ResourceError;
import miage.rest.routing.UriTemplateFinder;
import miage.rest.security.Roles;
import miage.rest.validation.DateValidator;
import miage.rest.validation.LengthValidator;
import miage.rest.validation.LongRangeValidator;
import miage.rest.validation.NotEmptyValidator;
import miage.rest.xml.XstreamRepresentation;
import miage.rest.xml.xstream.converter.HrefConverter;
import org.apache.commons.dbutils.DbUtils;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.restlet.resource.Put;
import org.restlet.resource.ResourceException;
import org.restlet.resource.ServerResource;

/**
 *
 * @author marya
 */
public class SessionResource extends ServerResource {

	private final Database database;
	private final UriTemplateFinder uriTemplateFinder;
	private SessionDiplome session;

	public SessionResource(Database database, UriTemplateFinder uriTemplateFinder) {
		this.database = database;
		this.uriTemplateFinder = uriTemplateFinder;
	}

	@Override
	protected void doInit() throws ResourceException {
		final String sqlSession = "SELECT id_session,nom,date_debut,date_fin FROM session_diplome WHERE id_session = ?";

		Long idSession = null;
		String idSessionAttribute = getRequest().getAttributes().get("idSession").toString();
		LongRangeValidator longRangeValidator = new LongRangeValidator(1l, null);

		//Validation de l'id de la session
		if (longRangeValidator.isValid(idSessionAttribute)) {
			idSession = Long.parseLong(idSessionAttribute);
		} else {
			getResponse().setEntity(ResourceError.getNewRepresentation("invalidSessionId"));
			throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST);
		}
		
		//Vérification d'existence de la session
		try {
			session = database.fetchRow(sqlSession, SessionDiplome.class,
										idSession);
			if (session == null) {
				setExisting(false);
			}
			
		} catch (SQLException ex) {
			throw new ResourceException(Status.SERVER_ERROR_INTERNAL, ex);
		}
	}

	@Get
	public Representation doGet() throws Exception {
		Representation response = null;

		response = new XstreamRepresentation<SessionDiplome>(session);
		
		return response;
	}

	@Post
	public Representation doPost(Representation entity) throws Exception {
		
		Representation result = null;
		Connection connexion = null;
		Candidature candidature = null;

		final String sqlCandidat = "SELECT id_candidat, email FROM candidat WHERE id_candidat = ?";
		final String sqlCandidature = "INSERT INTO candidature "
				+ "(id_candidat,id_session,id_statut,commentaire,date_effet)"
				+ " VALUES"
				+ "(?,?,?,?,NOW())";
		final String findCandidature = "SELECT id_candidature "
										+ "FROM candidature "
										+ "WHERE id_candidat = ? AND id_session = ?";

		List<ResourceError> errors = new ArrayList<ResourceError>();
		String idCandidatAttribute = getRequest().getAttributes().get("idCandidat").toString();
		Candidat candidat = null;
		LongRangeValidator longRangeValidator = new LongRangeValidator(1l, null);

		//Validation de l'id du candidat
		if (!longRangeValidator.isValid(idCandidatAttribute)) {

			setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "invalidIdCandidat");
			errors.add(new ResourceError(idCandidatAttribute + "is not a valid idCandidat"));

		} else {
			try {

				candidat = database.fetchRow(sqlCandidat, Candidat.class, Long.parseLong(idCandidatAttribute));
				
				if (candidat == null) {
					setStatus(Status.CLIENT_ERROR_NOT_FOUND);
					errors.add(new ResourceError("Impossible de trouver le candidat"));
				} else {

					//Test de l'existance de la candidature de ce candidat pour cette session
					candidature = database.fetchRow(
							findCandidature,
							Candidature.class,
							candidat.getIdCandidat(),
							session.getIdSession());
					
					if (candidature != null) {
						
						setStatus(Status.CLIENT_ERROR_CONFLICT);
						errors.add(new ResourceError("Candidature already exists"));

					} else {

						Form form = new Form(entity);
						form.addValidator("commentaire", new LengthValidator(250));

						if (!form.isValid()) {
							for (String error : form.getMessages()) {
								errors.add(new ResourceError(error));
							}
							setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
						} else {

							//On ajoute la nouvelle candidature
							connexion = database.getNewConnection();
							connexion.setAutoCommit(false);
							
							Integer insertedCandidature = database.update(
									connexion,
									sqlCandidature,
									candidat.getIdCandidat(),
									session.getIdSession(),
									4,
									form.getFirstValue("commentaire")).getGeneratedKeys();

							if (insertedCandidature == null || insertedCandidature < 1) {
								errors.add(new ResourceError("Impossible de créer le candidature"));
								setStatus(Status.SERVER_ERROR_INTERNAL);
							} else {
								
								result = new XstreamRepresentation<Candidature>(new Candidature(
										insertedCandidature));
								XStream xstream = ((XstreamRepresentation) result).getXstream();
								xstream.registerConverter(new HrefConverter(
										Candidature.class,
										xstream.getConverterLookup(),
										uriTemplateFinder.find(
										CandidatureResource.class)));

								connexion.commit();
								
								setStatus(Status.SUCCESS_CREATED);
								
							}

						}

					}
				}
			} catch (SQLException exc) {
				DbUtils.rollbackAndCloseQuietly(connexion);
				throw exc;
			}
		}
		
		if (!errors.isEmpty()) {
			result = ResourceError.getNewRepresentation(errors);
		}
		
		return result;
	}

	@Put
	public Representation doPut(Representation entity) throws Exception {

		if (!isInRole(Roles.ADMIN.getName())) {
			throw new ResourceException(Status.CLIENT_ERROR_UNAUTHORIZED);
		}

		Representation response = null;
		List<ResourceError> errors = new ArrayList<ResourceError>();
		Form form = getNewSessionForm(entity);

		if (!form.isValid()) {

			for (String error : form.getMessages()) {
				errors.add(new ResourceError(error));
			}
			setStatus(Status.CLIENT_ERROR_BAD_REQUEST);

		} else {

			String nom = form.getFirstValue("nom");
			SimpleDateFormat sD = new SimpleDateFormat("y-m-d");
			Date dateDebut = new Date(sD.parse(form.getFirstValue("dateDebut")).getTime());
			Date dateFin = new Date(sD.parse(form.getFirstValue("dateFin")).getTime());

			String nouvelleSession = "UPDATE session_diplome SET nom = ?, date_debut = ?, date_fin = ? WHERE id_session = ?";
			database.update(nouvelleSession, nom, dateDebut, dateFin,session.getIdSession());

			response = new XstreamRepresentation<SessionDiplome>(new SessionDiplome(
					session.getIdSession()));
			XStream xstream = ((XstreamRepresentation) response).getXstream();
			xstream.registerConverter(new HrefConverter(
					SessionDiplome.class,
					xstream.getConverterLookup(),
					uriTemplateFinder.find(SessionResource.class)));

		}
		
		if (!errors.isEmpty()) {
			response = ResourceError.getNewRepresentation(errors);
		}
		return response;
	}

	@SuppressWarnings("unchecked")
	private Form getNewSessionForm(Representation entity) {
		Form form = new Form(entity);

		DateValidator dateValidator = new DateValidator("y-m-d", "yyyy-mm-dd");
		NotEmptyValidator notEmptyValidator = new NotEmptyValidator();
		LengthValidator lengthValidator = new LengthValidator(250);
		form.addValidators("nom", notEmptyValidator, lengthValidator);
		form.addValidators("dateDebut", notEmptyValidator, dateValidator);
		form.addValidators("dateFin", notEmptyValidator, dateValidator);

		return form;
	}
}
